﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;

namespace RecruitmentAgency.Models.Utilities
{
    /// <summary>
    /// This class is responsible for the Password encryption.
    /// It uses a SHA256 hash plus a random geneared Salt
    /// </summary>
    public class Encryption
    {        
        /// <summary>
        /// Generate a random Salt
        /// </summary>
        /// <returns>Salt as byte[]</returns>
        private static byte[] GetRandomSalt()
        {
            const int minSaltSize = 16;
            const int maxSaltSize = 32;

            Random random = new Random();
            int saltSize = random.Next(minSaltSize, maxSaltSize);
            byte[] saltBytes = new byte[saltSize];
            RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
            rng.GetNonZeroBytes(saltBytes);
            return saltBytes;
        }


        /// <summary>
        /// Encrypt the text with SHA256 hash function
        /// </summary>
        /// <param name="plainText">The text to encrypt</param>
        /// <returns>Hashed text as byte[]</returns>
        private static byte[] ComputeHash(string plainText)
        {
            byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText);
            HashAlgorithm hash = new SHA256Managed();
            return hash.ComputeHash(plainTextBytes);
        }

        /// <summary>
        /// Hash the username, password, and salt
        /// </summary>
        /// <param name="username">The Username</param>
        /// <param name="password">The user Password</param>
        /// <returns>A dictionary byte[], string containing an Hashed salt, hashed password composed by
        ///          the hashed username + the hashed salt + the hashed password</returns>
        public static Dictionary<byte[], byte[]> Encrypt(string username, string password)
        {
            byte[] salt = GetRandomSalt();
            byte[] encryptedPassword = (ComputeHash(username + SaltToString(salt)).Concat(salt).Concat(ComputeHash(password)).ToArray());
            Dictionary<byte[], byte[]> encryption = new Dictionary<byte[], byte[]> { { salt.ToArray(), encryptedPassword.ToArray() } };
            return encryption;
        }

        /// <summary>
        /// Creates an Encrypted password
        /// </summary>
        /// <param name="username">The user username</param>
        /// <param name="password">The user password</param>
        /// <param name="salt">The user asigne encryption key</param>
        /// <returns>A dictionary containing the salt key and the encrypted password</returns>
        public static Dictionary<byte[], byte[]> RestoreEncryptedPassword(string username, string password, byte[] salt)
        {            
            byte[] encryptedPassword = (ComputeHash(username + SaltToString(salt)).Concat(salt).Concat(ComputeHash(password)).ToArray());
            Dictionary<byte[], byte[]> encryption = new Dictionary<byte[], byte[]> { { salt.ToArray(), encryptedPassword.ToArray() } };
            return encryption;
        }       

        /// <summary>
        /// Converts the Salt bytes array into a string
        /// </summary>
        /// <param name="salt">An array of byte the key to convert</param>
        /// <returns>The encrypted key as string</returns>
        public static string SaltToString(byte[] salt)
        {
            Encoding enc = Encoding.ASCII;
            return enc.GetString(salt);
        }
    }
}